﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;

namespace Fast.Extensions.DatabaseAccessor.EntityFrameworkCore
{
    /// <summary>
    /// 工作单元
    /// </summary>
    [SkipScan]
    public class UnitOfWork : IUnitOfWork
    {
        private readonly IDbContextManager _dbContextManager;
        /// <summary>
        /// 数据库上下文集合
        /// </summary>
        public ConcurrentDictionary<Guid, DbContext> DbContexts { get; private set; }
        /// <summary>
        /// 数据库上下文事务
        /// </summary>
        public IDbContextTransaction DbContextTransaction { get; private set; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext"></param>
        public UnitOfWork(IDbContextManager dbContextManager)
        {
            _dbContextManager = dbContextManager;

            DbContexts = _dbContextManager.GetDbContexts();
        }
        /// <summary>
        /// 开启事务
        /// </summary>
        public IDbContextTransaction Begin()
        {
            if (DbContexts.Any())
            {
                if (DbContextTransaction != null)
                {
                    return DbContextTransaction;
                }

                DbContextTransaction = DbContexts.First().Value.Database.BeginTransaction();

                var dbTransaction = DbContextTransaction.GetDbTransaction();
                //对其它上下文设置共享事务
                DbContexts.Where(p => p.Value.Database.CurrentTransaction == null)
                    .Select(p => p.Value.Database.UseTransaction(dbTransaction));

                App.PrintToMiniProfiler(MiniProfilerCategory.UnitOfWork.GetDescription(), $"Begin", $"BeginTransaction()");
            }
            else
            {
                throw new InvalidOperationException("找不到数据库上下文,无法开启事务");
            }

            return DbContextTransaction;
        }

        /// <summary>
        /// 开启事务
        /// </summary>
        public async Task<IDbContextTransaction> BeginAsync()
        {
            if (DbContexts.Any())
            {
                if (DbContextTransaction != null)
                {
                    return DbContextTransaction;
                }

                DbContextTransaction = await DbContexts.First().Value.Database.BeginTransactionAsync();

                var dbTransaction = DbContextTransaction.GetDbTransaction();
                //对其它上下文设置共享事务
                foreach (var item in DbContexts.Where(p => p.Value.Database.CurrentTransaction == null))
                {
                    item.Value.Database.UseTransaction(dbTransaction);
                }
                App.PrintToMiniProfiler(MiniProfilerCategory.UnitOfWork.GetDescription(), $"BeginAsync", $"BeginTransactionAsync()");
            }
            else
            {
                throw new InvalidOperationException("找不到数据库上下文,无法开启事务");
            }

            return DbContextTransaction;
        }

        /// <summary>
        /// 提交事务
        /// </summary>
        /// <param name="contextTransaction"></param>
        public void Commit()
        {
            if (DbContextTransaction != null)
            {
                App.PrintToMiniProfiler(MiniProfilerCategory.UnitOfWork.GetDescription(), $"Commit", $"Commit()");

                DbContextTransaction.Commit();
            }
        }

        /// <summary>
        /// 提交事务
        /// </summary>
        /// <param name="contextTransaction"></param>
        /// <returns></returns>
        public async Task CommitAsync()
        {
            if (DbContextTransaction != null)
            {
                App.PrintToMiniProfiler(MiniProfilerCategory.UnitOfWork.GetDescription(), $"CommitAsync", $"CommitAsync()");

                await DbContextTransaction.CommitAsync();
            }
        }

        /// <summary>
        /// 回滚事务
        /// </summary>
        public void Rollback()
        {
            if (DbContextTransaction != null)
            {
                App.PrintToMiniProfiler(MiniProfilerCategory.UnitOfWork.GetDescription(), $"Rollback", $"Rollback()");

                DbContextTransaction.Rollback();
            }
        }

        /// <summary>
        /// 回滚事务
        /// </summary>
        public async Task RollbackAsync()
        {
            if (DbContextTransaction != null)
            {
                App.PrintToMiniProfiler(MiniProfilerCategory.UnitOfWork.GetDescription(), $"RollbackAsync", $"RollbackAsync()");

                await DbContextTransaction.RollbackAsync();
            }
        }
    }
}
